#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "sockettj.h"

void options_set_timeout(int fd_socket, int timeout) {
	struct timeval tv;
	tv.tv_sec = timeout;
	tv.tv_usec = 0;
	if (-1 == setsockopt(fd_socket, SOL_SOCKET, SO_SNDTIMEO, (char*) &tv, sizeof(tv))) {
		perror("options_set_timeout");
		exit(1);
	}
	if (-1 == setsockopt(fd_socket, SOL_SOCKET, SO_RCVTIMEO, (char*) &tv, sizeof(tv))) {
		perror("options_set_timeout");
		exit(1);
	}
}
void options_set_reuse(int fd_socket) {
	int option = 1;
	if (-1 == setsockopt(fd_socket, SOL_SOCKET, SO_REUSEADDR, (const char*) &option, sizeof(option))) {
		perror("options_set_reuse");
		exit(1);
	}
#ifdef SO_REUSEPORT
	if (-1 == setsockopt(fd_socket, SOL_SOCKET, SO_REUSEPORT, (const char*) &option, sizeof(option))) {
		perror("options_set_reuse");
		exit(1);
	}
#endif
}
void get_remote_address(int port, char* ip, struct sockaddr_in* result) {
	struct sockaddr_in address = *result;
	bzero(&address, sizeof(address));
	address.sin_family = AF_INET;
	address.sin_port = htons(port);
	struct hostent *host;
	if ((host = gethostbyname(ip)) == NULL) {
		perror("gethostbyname()");
		exit(1);
	}
	address.sin_addr = *((struct in_addr*) host->h_addr_list[0]);
	*result = address;
}
int create_client_tcp(char* ip, int port) {
	int fd_socket = socket(AF_INET, SOCK_STREAM, 0);
	options_set_timeout(fd_socket, 3);
	options_set_reuse(fd_socket);
	struct sockaddr_in address;
	get_remote_address(port, ip, &address);
	if (connect(fd_socket, (struct sockaddr *) &address, sizeof(struct sockaddr)) == -1) {
		perror("connect()");
		printf("socket(%i), ip(%s), port(%i)\n", fd_socket, ip, port);
		exit(1);
	}
	return fd_socket;
}

int open_bind(int port) {

	int flag = 1, len = sizeof(int);
	int fd_socket;
	if ((fd_socket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		perror("Creating socket failed.");
		exit(1);
	}
	int option = SO_REUSEADDR;
	setsockopt(fd_socket, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
	int timeout = 30;
	setsockopt(fd_socket, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(int));
	setsockopt(fd_socket, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(int));

	struct sockaddr_in address_server;
	bzero(&address_server, sizeof(address_server));
	address_server.sin_family = AF_INET;
	address_server.sin_port = htons(port);
	address_server.sin_addr.s_addr = htonl(INADDR_ANY);

	if (setsockopt(fd_socket, SOL_SOCKET, SO_REUSEADDR, &flag, len) == -1) {
		perror("setsockopt");
		exit(1);
	}

	if (bind(fd_socket, (struct sockaddr *) &address_server, sizeof(struct sockaddr)) == -1) {
		perror("Bind error.");
		exit(1);
	}

	if (listen(fd_socket, 2) == -1) {
		perror("listen() error\n");
		exit(1);
	}
	return fd_socket;
}
void send_file(char* path, int df_connect) {
	FILE *stream = fopen(path, "rb");
	if (stream == NULL)
		perror("Error opening file");
	else {
		fseek(stream, 0, SEEK_SET);
		char line[256];
		while (NULL != fgets(line, 256, stream)) {
			send(df_connect, line, strlen(line), 0);
		}
		fclose(stream);
	}
}

char* ip_search(void) {
	int fd = socket(AF_INET, SOCK_DGRAM, 0);
	if (fd < 0)
		return "";
	struct ifreq request[16];
	struct ifconf ifconfig;
	ifconfig.ifc_len = sizeof(request);
	ifconfig.ifc_buf = (caddr_t) request;
	if (ioctl(fd, SIOCGIFCONF, (char *) &ifconfig))
		return "";
	int length = ifconfig.ifc_len / sizeof(struct ifreq);
	while (length-- > 0 && ioctl(fd, SIOCGIFADDR, (char *) &request[length]))
		;
	close(fd);
	return inet_ntoa(((struct sockaddr_in*) (&request[length].ifr_addr))-> sin_addr);
}
void change_ip_address(char* ip) {
	while (*ip++) {
		if (*ip == '.') {
			*ip = ',';
		}
	}
}

void get_file_name(char filepath[], char name[]) {
	int i;
	int start = 0;
	for (i = 0; i < strlen(filepath); i++) {
		if (filepath[i] == '/' || filepath[i] == '\\') {
			start = i + 1;
		}
		name[i - start] = filepath[i];
	}
}
